#include "exception_handler.h"
#include <ObjBase.h>

#include <algorithm>
#include <cassert>
#include <cstdio>

#include "common/windows/guid_string.h"

typedef VOID (WINAPI *RtlCaptureContextPtr)(PCONTEXT pContextRecord);

namespace longkey_breakpad
{
	static const int kWaitForHandlerThreadMs = 60000;
	static const int kExceptionHandlerThreadInitialStackSize = 64 * 1024;

	// This is passed as the context to the MinidumpWriteDump callback.
	typedef struct  
	{
		ULONG64 memory_base;
		ULONG   memory_size;
		bool    finished;
	} MinidumpCallbackContext;

	vector<ExceptionHandler*>* ExceptionHandler::handler_stack_ = NULL;
	LONG ExceptionHandler::handler_stack_index_ = 0;
	CRITICAL_SECTION ExceptionHandler::handler_stack_critical_section_;
	volatile LONG ExceptionHandler::instance_count_ = 0;

	ExceptionHandler::ExceptionHandler(const wstring& dump_path, 
		FilterCallback filter, 
		MinidumpCallback callback, void* callback_context, 
		int handler_types, MINIDUMP_TYPE dump_type, const wchar_t* pipe_name, 
		const CustomClientInfo* custom_info)
	{
		Initialize(dump_path, filter, callback, callback_context,
			handler_types, dump_type, pipe_name, custom_info);
	}

	ExceptionHandler::ExceptionHandler(const wstring& dump_path, FilterCallback filter, 
		MinidumpCallback callback, void* callback_context, int handler_types)
	{
		Initialize(dump_path, filter, callback, callback_context,
			handler_types, MiniDumpNormal, NULL, NULL);
	}

	void ExceptionHandler::Initialize(const wstring& dump_path, FilterCallback filter, 
		MinidumpCallback callback, void* callback_context, 
		int handler_types, MINIDUMP_TYPE dump_type, 
		const wchar_t* pipe_name, const CustomClientInfo* custom_info)
	{
		LONG instance_count = InterlockedIncrement(&instance_count_);
		filter_ = filter;
		callback_ = callback;
		callback_context_ = callback_context;
		dump_path_c_ = NULL;
		next_minidump_id_c_ = NULL;
		next_minidump_path_c_ = NULL;
		dbghelp_module_ = NULL;
		minidump_write_dump_ = NULL;
		dump_type_ = dump_type;
		rpcrt4_module_ = NULL;
		uuid_create_ = NULL;
		handler_types_ = handler_types;
		previous_filter_ = NULL;
#if _MSC_VER >= 1400  // MSVC 2005/8
		previous_iph_ = NULL;
#endif  // _MSC_VER >= 1400
		previous_pch_ = NULL;
		handler_thread_ = NULL;
		is_shutdown_ = false;
		handler_start_semaphore_ = NULL;
		handler_finish_semaphore_ = NULL;
		requesting_thread_id_ = 0;
		exception_info_ = NULL;
		assertion_ = NULL;
		handler_return_value_ = false;
		handle_debug_exceptions_ = false;

		// Attempt to use out-of-process if user has specified pipe name.
		if (pipe_name != NULL)
		{
			scoped_ptr<CrashGenerationClient> client(
				new CrashGenerationClient(pipe_name, dump_type_, custom_info));

			// If successful in registering with the monitoring process,
			// there is no need to setup in-process crash generation.
			if (client->Register())
				crash_generation_client_.reset(client.release());
		}

		if (!IsOutOfProcess())
		{
			// Either client did not ask for out-of-process crash generation
			// or registration with the server process failed. In either case,
			// setup to do in-process crash generation.

			// Set synchronization primitives and the handler thread.  Each
			// ExceptionHandler object gets its own handler thread because that's the
			// only way to reliably guarantee sufficient stack space in an exception,
			// and it allows an easy way to get a snapshot of the requesting thread's
			// context outside of an exception.
			InitializeCriticalSection(&handler_critical_section_);
			handler_start_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
			assert(handler_start_semaphore_ != NULL);

			handler_finish_semaphore_ = CreateSemaphore(NULL, 0, 1, NULL);
			assert(handler_finish_semaphore_ != NULL);

			// Don't attempt to create the thread if we could not create the semaphores.
			if (handler_finish_semaphore_ != NULL && handler_start_semaphore_ != NULL)
			{
				DWORD thread_id;
				handler_thread_ = CreateThread(NULL,
					kExceptionHandlerThreadInitialStackSize,
					ExceptionHandlerThreadMain, this, 0, &thread_id);
				assert(handler_thread_ != NULL);
			}

			dbghelp_module_ = LoadLibrary(L"dbghelp.dll");
			if (dbghelp_module_)
				minidump_write_dump_ = reinterpret_cast<MiniDumpWriteDump_type>(
					GetProcAddress(dbghelp_module_, "MiniDumpWriteDump"));

			// Load this library dynamically to not affect existing projects.  Most
			// projects don't link against this directly, it's usually dynamically
			// loaded by dependent code.
			rpcrt4_module_ = LoadLibrary(L"rpcrt4.dll");
			if (rpcrt4_module_) 
				uuid_create_ = reinterpret_cast<UuidCreate_type>(
					GetProcAddress(rpcrt4_module_, "UuidCreate"));
			
			// set_dump_path calls UpdateNextID.  This sets up all of the path and id
			// strings, and their equivalent c_str pointers.
			set_dump_path(dump_path);
		}

		// There is a race condition here. If the first instance has not yet
		// initialized the critical section, the second (and later) instances may
		// try to use uninitialized critical section object. The feature of multiple
		// instances in one module is not used much, so leave it as is for now.
		// One way to solve this in the current design (that is, keeping the static
		// handler stack) is to use spin locks with volatile bools to synchronize
		// the handler stack. This works only if the compiler guarantees to generate
		// cache coherent code for volatile.
		// TODO(munjal): Fix this in a better way by changing the design if possible.

		// Lazy initialization of the handler_stack_critical_section_
		if (instance_count == 1)
			InitializeCriticalSection(&handler_stack_critical_section_);

		if (handler_types != HANDLER_NONE)
		{
			EnterCriticalSection(&handler_stack_critical_section_);

			// The first time an ExceptionHandler that installs a handler is
			// created, set up the handler stack.
			if (!handler_stack_)
				handler_stack_ = new vector<ExceptionHandler*>();

			handler_stack_->push_back(this);

			if (handler_types & HANDLER_EXCEPTION)
				previous_filter_ = SetUnhandledExceptionFilter(HandleException);

#if _MSC_VER >= 1400
			if (handler_types & HANDLER_INVALID_PARAMETER)
				previous_iph_ = _set_invalid_parameter_handler(HandleInvalidParameter);
#endif
			if (handler_types & HANDLER_PURECALL)
				previous_pch_ = _set_purecall_handler(HandlePureVirtualCall);

			LeaveCriticalSection(&handler_stack_critical_section_);
		}
	}

	ExceptionHandler::~ExceptionHandler()
	{
		if (dbghelp_module_)
			FreeLibrary(dbghelp_module_);

		if (rpcrt4_module_)
			FreeLibrary(rpcrt4_module_);

		if (handler_types_ != HANDLER_NONE)
		{
			EnterCriticalSection(&handler_stack_critical_section_);
			if (handler_types_ & HANDLER_EXCEPTION)
				SetUnhandledExceptionFilter(previous_filter_);

#if _MSC_VER >= 1400  // MSVC 2005/8
			if (handler_types_ & HANDLER_INVALID_PARAMETER)
				_set_invalid_parameter_handler(previous_iph_);
#endif  // _MSC_VER >= 1400

			if (handler_types_ & HANDLER_PURECALL)
				_set_purecall_handler(previous_pch_);

			if (handler_stack_->back() == this) 
				handler_stack_->pop_back();
			else
			{
				// TODO: use advapi32!ReportEvent to log the warning to the
				// system's application event log.
				fprintf(stderr, "warning: removing Breakpad handler out of order\n");
				vector<ExceptionHandler*>::iterator iterator = handler_stack_->begin();
				while (iterator != handler_stack_->end())
				{
					if (*iterator == this) 
						iterator = handler_stack_->erase(iterator);
					else
						++iterator;
				}
			}

			if (handler_stack_->empty())
			{
				// When destroying the last ExceptionHandler that installed a handler,
				// clean up the handler stack.
				delete handler_stack_;
				handler_stack_ = NULL;
			}
			LeaveCriticalSection(&handler_stack_critical_section_);
		}

		// Some of the objects were only initialized if out of process
		// registration was not done.
		if (!IsOutOfProcess())
		{
#ifdef BREAKPAD_NO_TERMINATE_THREAD
			// Clean up the handler thread and synchronization primitives. The handler
			// thread is either waiting on the semaphore to handle a crash or it is
			// handling a crash. Coming out of the wait is fast but wait more in the
			// eventuality a crash is handled.  This compilation option results in a
			// deadlock if the exception handler is destroyed while executing code
			// inside DllMain.
			is_shutdown_ = true;
			ReleaseSemaphore(handler_start_semaphore_, 1, NULL);
			WaitForSingleObject(handler_thread_, kWaitForHandlerThreadMs);
#else
			TerminateThread(handler_thread_, 1);
#endif	// BREAKPAD_NO_TERMINATE_THREAD

			CloseHandle(handler_thread_);
			handler_thread_ = NULL;
			DeleteCriticalSection(&handler_critical_section_);
			CloseHandle(handler_start_semaphore_);
			CloseHandle(handler_finish_semaphore_);
		}

		// There is a race condition in the code below: if this instance is
		// deleting the static critical section and a new instance of the class
		// is created, then there is a possibility that the critical section be
		// initialized while the same critical section is being deleted. Given the
		// usage pattern for the code, this race condition is unlikely to hit, but it
		// is a race condition nonetheless.
		if (InterlockedDecrement(&instance_count_) == 0)
			DeleteCriticalSection(&handler_stack_critical_section_);
	}

	// static
	DWORD ExceptionHandler::ExceptionHandlerThreadMain(void* lpParameter)
	{
		ExceptionHandler* self = reinterpret_cast<ExceptionHandler*>(lpParameter);
		assert(self);
		assert(self->handler_start_semaphore_ != NULL);
		assert(self->handler_finish_semaphore_ != NULL);

		while (true)
		{
			if (WaitForSingleObject(self->handler_start_semaphore_, INFINITE) == WAIT_OBJECT_0)
			{
				// Perform the requested action
				if (self->is_shutdown_)
					break;
				else				
					self->handler_return_value_ = self->WriteMinidumpWithException(
						self->requesting_thread_id_,
						self->exception_info_,
						self->assertion_);
				
				// Allow the requesting thread to procceed.
				ReleaseSemaphore(self->handler_finish_semaphore_, 1, NULL);
			}
		}

		// This statement is not reached when the thread is unconditionally
		// terminated by the ExceptionHandler destructor.
		return 0;
	}

	// HandleException and HandleInvalidParameter must create an
	// AutoExceptionHandler object to maintain static state and to determine which
	// ExceptionHandler instance to use.  The constructor locates the correct
	// instance, and makes it available through get_handler().  The destructor
	// restores the state in effect prior to allocating the AutoExceptionHandler.
	class AutoExceptionHandler
	{
	public:
		AutoExceptionHandler()
		{
			// Increment handler_stack_index_ so that if another Breakpad handler is
			// registered using this same HandleException function, and it needs to be
			// called while this handler is running (either because this handler
			// declines to handle the exception, or an exception occurs during
			// handling), HandleException will find the appropriate ExceptionHandler
			// object in handler_stack_ to deliver the exception to.
			//
			// Because handler_stack_ is addressed in reverse (as |size - index|),
			// preincrementing handler_stack_index_ avoids needing to subtract 1 from
			// the argument to |at|.
			//
			// The index is maintained instead of popping elements off of the handler
			// stack and pushing them at the end of this method.  This avoids ruining
			// the order of elements in the stack in the event that some other thread
			// decides to manipulate the handler stack (such as creating a new
			// ExceptionHandler object) while an exception is being handled.
			EnterCriticalSection(&ExceptionHandler::handler_stack_critical_section_);

			handler_ = ExceptionHandler::handler_stack_->at(
				ExceptionHandler::handler_stack_->size() -
				++ExceptionHandler::handler_stack_index_);

			// In case another exception occurs while this handler is doing its thing,
			// it should be delivered to the previous filter.
			SetUnhandledExceptionFilter(handler_->previous_filter_);
#if _MSC_VER >= 1400  // MSVC 2005/8
			_set_invalid_parameter_handler(handler_->previous_iph_);
#endif  // _MSC_VER >= 1400
			_set_purecall_handler(handler_->previous_pch_);
		}

		~AutoExceptionHandler()
		{
			// Put things back the way they were before entering this handler.
			SetUnhandledExceptionFilter(ExceptionHandler::HandleException);
#if _MSC_VER >= 1400  // MSVC 2005/8
			_set_invalid_parameter_handler(ExceptionHandler::HandleInvalidParameter);
#endif  // _MSC_VER >= 1400
			_set_purecall_handler(ExceptionHandler::HandlePureVirtualCall);

			--ExceptionHandler::handler_stack_index_;
			LeaveCriticalSection(&ExceptionHandler::handler_stack_critical_section_);
		}

		ExceptionHandler* get_handler() const { return handler_; }
	private:
		ExceptionHandler* handler_;
	};

	// static
	LONG ExceptionHandler::HandleException(EXCEPTION_POINTERS* exinfo)
	{
		AutoExceptionHandler auto_exception_handler;
		ExceptionHandler* current_handler = auto_exception_handler.get_handler();

		// Ignore EXCEPTION_BREAKPOINT and EXCEPTION_SINGLE_STEP exceptions.  This
		// logic will short-circuit before calling WriteMinidumpOnHandlerThread,
		// allowing something else to handle the breakpoint without incurring the
		// overhead transitioning to and from the handler thread.  This behavior
		// can be overridden by calling ExceptionHandler::set_handle_debug_exceptions.
		DWORD code = exinfo->ExceptionRecord->ExceptionCode;
		LONG action;
		bool is_debug_exception = (code == EXCEPTION_BREAKPOINT ||
			code == EXCEPTION_SINGLE_STEP);
		bool success = false;

		if (!is_debug_exception || current_handler->get_handle_debug_exceptions())
		{
			// If out-of-proc crash handler client is available, we have to use that
			// to generate dump and we cannot fall back on in-proc dump generation
			// because we never prepared for an in-proc dump generation

			// In case of out-of-process dump generation, directly call
			// WriteMinidumpWithException since there is no separate thread running.
			if (current_handler->IsOutOfProcess())
				success = current_handler->WriteMinidumpWithException(GetCurrentThreadId(),
				 exinfo, NULL);
			else
				success = current_handler->WriteMinidumpOnHandlerThread(exinfo, NULL);
		}

		// The handler fully handled the exception.  Returning
		// EXCEPTION_EXECUTE_HANDLER indicates this to the system, and usually
		// results in the application being terminated.
		//
		// Note: If the application was launched from within the Cygwin
		// environment, returning EXCEPTION_EXECUTE_HANDLER seems to cause the
		// application to be restarted.
		if (success)
			action = EXCEPTION_EXECUTE_HANDLER;
		else
		{
			// There was an exception, it was a breakpoint or something else ignored
			// above, or it was passed to the handler, which decided not to handle it.
			// This could be because the filter callback didn't want it, because
			// minidump writing failed for some reason, or because the post-minidump
			// callback function indicated failure.  Give the previous handler a
			// chance to do something with the exception.  If there is no previous
			// handler, return EXCEPTION_CONTINUE_SEARCH, which will allow a debugger
			// or native "crashed" dialog to handle the exception.
			if (current_handler->previous_filter_)
				action = current_handler->previous_filter_(exinfo);
			else
				action = EXCEPTION_CONTINUE_SEARCH;
		}
		return action;
	}

#if _MSC_VER >= 1400  // MSVC 2005/8
	// static
	void ExceptionHandler::HandleInvalidParameter(const wchar_t* expression, 
		const wchar_t* function, const wchar_t* file, unsigned int line, uintptr_t reserved)
	{
		// This is an invalid parameter, not an exception. It's safe to play with
		// sprintf here.
		AutoExceptionHandler auto_exception_handler;
		ExceptionHandler* current_handler = auto_exception_handler.get_handler();

		MDRawAssertionInfo assertion;
		memset(&assertion, 0, sizeof(assertion));
		_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.expression), 
			sizeof(assertion.expression) / sizeof(assertion.expression[0]), 
			_TRUNCATE, L"%s", expression);
		_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.function), 
			sizeof(assertion.function) / sizeof(assertion.function[0]), 
			_TRUNCATE, L"%s", function);
		_snwprintf_s(reinterpret_cast<wchar_t*>(assertion.file), 
			sizeof(assertion.file) / sizeof(assertion.file[0]), 
			_TRUNCATE, L"%s", file);
		assertion.line = line;
		assertion.type = MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER;

		// Make up an exception record for the current thread and CPU context
		// to make it possible for the crash processor to classify thest
		// as do regular crashes, and to make it humane for developers to
		// analyze them.
		EXCEPTION_RECORD exception_record = {};
		CONTEXT exception_context = {};
		EXCEPTION_POINTERS exception_ptrs = {&exception_record, &exception_context};

		EXCEPTION_POINTERS* exinfo = NULL;

		RtlCaptureContextPtr fnRtlCaptureContext = (RtlCaptureContextPtr)
			GetProcAddress(GetModuleHandle(L"kernel32"), "RtlCaptureContext");
		if (fnRtlCaptureContext)
		{
			fnRtlCaptureContext(&exception_context);
			
			exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;

			// We store pointers to the expression and function strings,
			exception_record.NumberParameters = 3;
			exception_record.ExceptionInformation[0] =
				reinterpret_cast<ULONG_PTR>(&assertion.expression);
			exception_record.ExceptionInformation[1] =
				reinterpret_cast<ULONG_PTR>(&assertion.file);
			exception_record.ExceptionInformation[2] = assertion.line;

			exinfo = &exception_ptrs;
		}

		bool success = false;
		// In case of out-of-process dump generation, directly call
		// WriteMinidumpWithException since there is no sparate thread running.
		if (current_handler->IsOutOfProcess())
			success = current_handler->WriteMinidumpWithException(
				GetCurrentThreadId(), exinfo, &assertion);
		else
			success = current_handler->WriteMinidumpOnHandlerThread(exinfo, &assertion);

		if (!success)
		{
			if (current_handler->previous_iph_)
			{
				// The handler didn't fully handle the exception. Give it to the
				// previous invalid parameter handler.
				current_handler->previous_iph_(expression, function, file, line, reserved);
			}
			else
			{
				// If there's no previous handler, pass the exception back in to the
				// invalid parameter handler's core.  That's the routine that called this
				// function, but now, since this function is no longer registered (and in
				// fact, no function at all is registered), this will result in the
				// default code path being taken: _CRT_DEBUGGER_HOOK and _invoke_watson.
				// Use _invalid_parameter where it exists (in _DEBUG builds) as it passes
				// more information through.  In non-debug builds, it is not available,
				// so fall back to using _invalid_parameter_noinfo.  See invarg.c in the
				// CRT source.
#ifdef _DEBUG
				_invalid_parameter(expression, function, file, line, reserved);
#else  // _DEBUG
				_invalid_parameter_noinfo();
#endif  // _DEBUG
			}
		}

		// The handler either took care of the invalid parameter problem itself,
		// or passed it on to another handler.  "Swallow" it by exiting, paralleling
		// the behavior of "swallowing" exceptions.
		exit(0);
	}
#endif	// _MSC_VER >= 1400

	// static
	void ExceptionHandler::HandlePureVirtualCall()
	{
		// This is an pure virtual function call, not an exception. It's safe to
		// play with sprintf here.
		AutoExceptionHandler auto_exception_handler;
		ExceptionHandler* current_handler = auto_exception_handler.get_handler();

		MDRawAssertionInfo assertion;
		memset(&assertion, 0, sizeof(assertion));
		assertion.type = MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL;

		// Make up an exception record for the current thread and CPU context
		// to make it possible for the crash processor to classify these
		// as do regular crashes, and to make it humane for developers to
		// analyze them.
		EXCEPTION_RECORD exception_record = {};
		CONTEXT exception_context = {};
		EXCEPTION_POINTERS exception_ptrs = { &exception_record, &exception_context };

		EXCEPTION_POINTERS* exinfo = NULL;

		RtlCaptureContextPtr fnRtlCaptureContext = (RtlCaptureContextPtr)
			GetProcAddress(GetModuleHandleW(L"kernel32"), "RtlCaptureContext");
		if (fnRtlCaptureContext)
		{
			fnRtlCaptureContext(&exception_context);

			exception_record.ExceptionCode = STATUS_NONCONTINUABLE_EXCEPTION;

			// We store pointers to the the expression and function strings,
			// and the line as exception parameters to make them easy to
			// access by the developer on the far side.
			exception_record.NumberParameters = 3;
			exception_record.ExceptionInformation[0] =
				reinterpret_cast<ULONG_PTR>(&assertion.expression);
			exception_record.ExceptionInformation[1] =
				reinterpret_cast<ULONG_PTR>(&assertion.file);
			exception_record.ExceptionInformation[2] = assertion.line;

			exinfo = &exception_ptrs;
		}

		bool success = false;
		// In case of out-of-process dump generation, directly call
		// WriteMinidumpWithException since there is no separate thread running.

		if (current_handler->IsOutOfProcess())
		{
			success = current_handler->WriteMinidumpWithException(
				GetCurrentThreadId(),
				exinfo,
				&assertion);
		} else {
			success = current_handler->WriteMinidumpOnHandlerThread(exinfo,
				&assertion);
		}

		if (!success)
		{
			if (current_handler->previous_pch_) 
				// The handler didn't fully handle the exception.  Give it to the
				// previous purecall handler.
				current_handler->previous_pch_();
			 else 
				// If there's no previous handler, return and let _purecall handle it.
				// This will just put up an assertion dialog.
				return;			
		}

		// The handler either took care of the invalid parameter problem itself,
		// or passed it on to another handler.  "Swallow" it by exiting, paralleling
		// the behavior of "swallowing" exceptions.
		exit(0);
	}

	bool ExceptionHandler::WriteMinidumpOnHandlerThread(EXCEPTION_POINTERS* exinfo, MDRawAssertionInfo* assertion)
	{
		EnterCriticalSection(&handler_critical_section_);

		// There isn't much we can do if the handler thread
		// was not successfully created.
		if (handler_thread_ == NULL)
		{
			LeaveCriticalSection(&handler_critical_section_);
			return false;
		}

		// The handler thread should only be created when the semaphores are valid.
		assert(handler_start_semaphore_ != NULL);
		assert(handler_finish_semaphore_ != NULL);

		// Set up data to be passed into the handler thread.
		requesting_thread_id_ = GetCurrentThreadId();
		exception_info_ = exinfo;
		assertion_ = assertion;

		// This causes the handler thread to call WriteMinidumpWithException.
		ReleaseSemaphore(handler_start_semaphore_, 1, NULL);

		// Wait until WriteMinidumpWithException is done and collect its return value.
		WaitForSingleObject(handler_finish_semaphore_, INFINITE);
		bool status = handler_return_value_;

		// Clean up
		requesting_thread_id_ = 0;
		exception_info_ = NULL;
		assertion_ = NULL;

		LeaveCriticalSection(&handler_critical_section_);

		return status;
	}

	bool ExceptionHandler::WriteMinidump()
	{
		return WriteMinidumpForException(NULL);
	}

	bool ExceptionHandler::WriteMinidumpForException(EXCEPTION_POINTERS* exinfo)
	{
		// In case of out-of-process dump generation, directly call
		// WriteMinidumpForException since there is no separate thread running.
		if (IsOutOfProcess())
			return WriteMinidumpWithException(GetCurrentThreadId(), exinfo, NULL);

		bool success = WriteMinidumpOnHandlerThread(exinfo, NULL);
		UpdateNextID();
		return success;
	}

	// static
	bool ExceptionHandler::WriteMinidump(const wstring &dump_path, 
		MinidumpCallback callback, void* callback_context)
	{
		ExceptionHandler handler(dump_path, NULL, callback, callback_context, HANDLER_NONE);
		return handler.WriteMinidump();
	}

	bool ExceptionHandler::WriteMinidumpWithException(
		DWORD requesting_thread_id,
		EXCEPTION_POINTERS* exinfo,
		MDRawAssertionInfo* assertion)
	{
		// Give user code a chance to approve or prevent writing a minidump.  If the
		// filter returns false, don't handle the exception at all.  If this method
		// was called as a result of an exception, returning false will cause
		// HandleException to call any previous handler or return
		// EXCEPTION_CONTINUE_SEARCH on the exception thread, allowing it to appear
		// as though this handler were not present at all.
		if (filter_ && !filter_(callback_context_, exinfo, assertion)) 
			return false;
			
		bool success = false;
		if (IsOutOfProcess()) 
			success = crash_generation_client_->RequestDump(exinfo, assertion);
		else
		{
			if (minidump_write_dump_)
			{
				HANDLE dump_file = CreateFile(next_minidump_path_c_,
					GENERIC_WRITE,
					0,  // no sharing
					NULL,
					CREATE_NEW,  // fail if exists
					FILE_ATTRIBUTE_NORMAL,
					NULL);
				if (dump_file != INVALID_HANDLE_VALUE)
				{
					MINIDUMP_EXCEPTION_INFORMATION except_info;
					except_info.ThreadId = requesting_thread_id;
					except_info.ExceptionPointers = exinfo;
					except_info.ClientPointers = FALSE;

					// Add an MDRawBreakpadInfo stream to the minidump, to provide
					// additional information about the exception handler to the Breakpad
					// processor. The information will help the processor determine which
					// threads are relevant.  The Breakpad processor does not require this
					// information but can function better with Breakpad-generated dumps
					// when it is present. The native debugger is not harmed by the
					// presence of this information.
					MDRawBreakpadInfo breakpad_info;
					breakpad_info.validity = MD_BREAKPAD_INFO_VALID_DUMP_THREAD_ID |
						MD_BREAKPAD_INFO_VALID_REQUESTING_THREAD_ID;
					breakpad_info.dump_thread_id = GetCurrentThreadId();
					breakpad_info.requesting_thread_id = requesting_thread_id;

					// Leave room in user_stream_array for a possible assertion info stream.
					MINIDUMP_USER_STREAM user_stream_array[2];
					user_stream_array[0].Type = MD_BREAKPAD_INFO_STREAM;
					user_stream_array[0].BufferSize = sizeof(breakpad_info);
					user_stream_array[0].Buffer = &breakpad_info;

					MINIDUMP_USER_STREAM_INFORMATION user_streams;
					user_streams.UserStreamCount = 1;
					user_streams.UserStreamArray = user_stream_array;

					if (assertion)
					{
						user_stream_array[1].Type = MD_ASSERTION_INFO_STREAM;
						user_stream_array[1].BufferSize = sizeof(MDRawAssertionInfo);
						user_stream_array[1].Buffer = assertion;
						++user_streams.UserStreamCount;
					}

					MINIDUMP_CALLBACK_INFORMATION callback;
					MinidumpCallbackContext context;
					MINIDUMP_CALLBACK_INFORMATION* callback_pointer = NULL;
					// Older versions of DbgHelp.dll don't correctly put the memory around
					// the faulting instruction pointer into the minidump. This
					// callback will ensure that it gets included.
					if (exinfo)
					{
						// Find a memory region of 256 bytes centered on the
						// faulting instruction pointer.
						const ULONG64 instruction_pointer = 
#if defined(_M_IX86)
							exinfo->ContextRecord->Eip;
#elif defined(_M_AMD64)
							exinfo->ContextRecord->Rip;
#else
#error Unsupported platform
#endif

							MEMORY_BASIC_INFORMATION info;
						if (VirtualQuery(reinterpret_cast<LPCVOID>(instruction_pointer),
							&info,
							sizeof(MEMORY_BASIC_INFORMATION)) != 0 &&
							info.State == MEM_COMMIT) 
						{
							// Attempt to get 128 bytes before and after the instruction
							// pointer, but settle for whatever's available up to the
							// boundaries of the memory region.
							const ULONG64 kIPMemorySize = 256;
							context.memory_base =
								(std::max)(reinterpret_cast<ULONG64>(info.BaseAddress),
								instruction_pointer - (kIPMemorySize / 2));
							ULONG64 end_of_range =
								(std::min)(instruction_pointer + (kIPMemorySize / 2),
								reinterpret_cast<ULONG64>(info.BaseAddress)
								+ info.RegionSize);
							context.memory_size =
								static_cast<ULONG>(end_of_range - context.memory_base);

							context.finished = false;
							callback.CallbackRoutine = MinidumpWriteDumpCallback;
							callback.CallbackParam = reinterpret_cast<void*>(&context);
							callback_pointer = &callback;
						}
					}

					// The explicit comparison to TRUE avoids a warning (C4800).
					success = (minidump_write_dump_(GetCurrentProcess(),
						GetCurrentProcessId(),
						dump_file,
						dump_type_,
						exinfo ? &except_info : NULL,
						&user_streams,
						callback_pointer) == TRUE);

					CloseHandle(dump_file);
				}
			}
		}

		if (callback_) {
			// TODO: In case of out-of-process dump generation, both
			// dump_path_c_ and next_minidump_id_ will be NULL. For out-of-process
			// scenario, the server process ends up creating the dump path and dump
			// id so they are not known to the client.
			success = callback_(dump_path_c_, next_minidump_id_c_, callback_context_,
				exinfo, assertion, success);
		}

		return success;
	}

	// static
	BOOL CALLBACK ExceptionHandler::MinidumpWriteDumpCallback(
		PVOID context,
		const PMINIDUMP_CALLBACK_INPUT callback_input,
		PMINIDUMP_CALLBACK_OUTPUT callback_output)
	{
		switch (callback_input->CallbackType)
		{
		case MemoryCallback:
			{
				MinidumpCallbackContext* callback_context =
					reinterpret_cast<MinidumpCallbackContext*>(context);
				if (callback_context->finished)
					return FALSE;

				// Include the specified memory region.
				callback_output->MemoryBase = callback_context->memory_base;
				callback_output->MemorySize = callback_context->memory_size;
				callback_context->finished = true;
				return TRUE;
			}

			// Include all modules.
		case IncludeModuleCallback:
		case ModuleCallback:
			return TRUE;

			// Include all threads.
		case IncludeThreadCallback:
		case ThreadCallback:
			return TRUE;

			// Stop receiving cancel callbacks.
		case CancelCallback:
			callback_output->CheckCancel = FALSE;
			callback_output->Cancel = FALSE;
			return TRUE;
		}
		// Ignore other callback types.
		return FALSE;
	}

	void ExceptionHandler::UpdateNextID()
	{
		assert(uuid_create_);
		UUID id = {0};
		if (uuid_create_) 
			uuid_create_(&id);
		
		next_minidump_id_ = GUIDString::GUIDToWString(&id);
		next_minidump_id_c_ = next_minidump_id_.c_str();

		wchar_t minidump_path[MAX_PATH];
		swprintf(minidump_path, MAX_PATH, L"%s\\%s.dmp",
			dump_path_c_, next_minidump_id_c_);

		// remove when VC++7.1 is no longer supported
		minidump_path[MAX_PATH - 1] = L'\0';

		next_minidump_path_ = minidump_path;
		next_minidump_path_c_ = next_minidump_path_.c_str();
	}
}